﻿using System;
using System.Collections.Generic;
using Microsoft.SqlServer.Dts.Runtime;
using System.Xml;
using System.ComponentModel;
using System.Data.SqlClient;
using Shutterstock.Salesforce.SSISDownload;
using Shutterstock.Salesforce.SSISDownload.Logging;

using System.Diagnostics;
using Shutterstock.Salesforce.Tools;

namespace Shutterstock.Salesforce.SSISDownload.SSISTask
{
    /// <summary>
    /// Represents a SSIS Custom control flow componenet which refresh the sales force database.
    /// </summary>
    [DtsTask(
       DisplayName = "Salesforce Refresh Task",
       Description = "Refresh the SQL server salesforce database",
       TaskContact = "Salesforce Refresh Task",
      UITypeName = "Shutterstock.Salesforce.SSISDownload_UI.SFRefreshTaskUI,Shutterstock.Salesforce.SSISDownload_UI.2008R2,Version=1.0.0.0, Culture=Neutral,PublicKeyToken = ef13bcb45c185447"
   )]
    public class SFRefreshTask : Task, IDTSComponentPersist
    {
        #region Private Variables.
        int _maxThread = 4;
        string _sqlDestConMgr;
        int _batchSize = 10000;
        Connections _connections;
        string _password = string.Empty;
        string _userName = string.Empty;
        string _sqlConnectionString = string.Empty;
        ReportingLevel _messageLevel = ReportingLevel.High;
        bool _manualComparison = false;
        bool _bulkApi = true;
        int _bulkCutoff = 10000;
        int _maxRetries = 3;
        bool _defaultStatus= true; //Include
        string _tableName = String.Empty;
        string _columnName = String.Empty;
        bool _allowExceptions = false;
        string _forceBulkColumn = String.Empty;
        string _forceStandardColumn = String.Empty;
        string _objectColumnName = string.Empty;

        bool _sendDML = false;
        string _fromAddress = String.Empty;
        string _toAddress = String.Empty;
        string _smtp = String.Empty;

        #endregion

        #region Properties
        /// <summary>
        /// Get/set properties of the max number of Retries
        /// </summary>
        [Description("Specifies the max # of Retries for a failed object.")]
        public int MaxRetries
        {
            get { return _maxRetries; }
            set { _maxRetries = value; }
        }

        /// <summary>
        /// Get/set properties of the max number of threads
        /// </summary>
        [Description("Specifies the suggested max number of threads.")]
        public int MaxThread
        {
            get { return _maxThread; }
            set { _maxThread = value; }
        }
        /// <summary>
        /// Get/Set properties of the Sql Server destination database connection manager name
        /// </summary>
        [Description("Specifies the Sql Server Destination Database Connection name.")]
        public string SqlDestinationConnectionName
        {
            get { return GetConnectionName(_connections, _sqlDestConMgr); }
            set { _sqlDestConMgr = GetConnectionID(_connections, value); }
        }
        /// <summary>
        /// Get/Set properties of the batch size for bulk copy.
        /// </summary>
        [Description("Specifies the batch size for bulk copy.")]
        public int BatchSize
        {
            get { return _batchSize; }
            set { _batchSize = value; }
        }
        /// <summary>
        /// Get/Set properties of whether do manual comparison while deleting the data.
        /// </summary>
        [Description("Sepecifies whether do manual comparison while checking for deletion in the table.")]
        public bool ManualComparison
        {
            get { return _manualComparison; }
            set { _manualComparison = value; }

        }

        /// <summary>
        /// Get/Set of the password for the sales force database
        /// </summary>
        [PasswordPropertyText(true), Description("Specifies the password for the Sales force database.")]
        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }
        /// <summary>
        /// Get/Set prorperties the uase name for the Sales force database.
        /// </summary>
        [Description("Specifies the uase name for the Sales force database.")]
        public string UserName
        {
            get { return _userName; }
            set { _userName = value; }
        }
        /// <summary>
        /// Get/Set of the memssage level
        /// </summary>
        [Description("Specifies the message level for the log output.")]
        public ReportingLevel MessageLevel
        {
            get { return _messageLevel; }
            set { _messageLevel = value; }
        }

        /// <summary>
        /// Get/Set of the Usage of Bulk API
        /// </summary>
        [Description("Specifies whether or not to use the bulk API.")]
        public bool UseBulkAPI
        {
            get { return _bulkApi; }
            set { _bulkApi = value; }
        }

        /// <summary>
        /// Get/Set of the Bulk Cutoff level
        /// </summary>
        [Description("Specifies when to use the bulk API.")]
        public int BulkCutoff
        {
            get { return _bulkCutoff; }
            set { _bulkCutoff = value; }
        }

        /// <summary>
        /// Get/Set of the Bulk Cutoff level
        /// </summary>
        [Description("Specifies default to include or exclude.")]
        public bool DefaultStatus
        {
            get { return _defaultStatus; }
            set { _defaultStatus = value; }
        }

        /// <summary>
        /// Get/Set of the Bulk Cutoff level
        /// </summary>
        [Description("Specifies the Tablename where exceptions are held.")]
        public string ExceptionTableName
        {
            get { return _tableName; }
            set { _tableName = value; }
        }

        /// <summary>
        /// Get/Set of the Bulk Cutoff level
        /// </summary>
        [Description("Specifies ColumnName where exceptions are held.")]
        public string ExceptionColumnName
        {
            get { return _columnName; }
            set { _columnName = value; }
        }
        
        /// <summary>
        /// Get/Set of the Whether to Allow Exceptions at all, or just load everything
        /// </summary>
        [Description("Specifies Whether to allow exceptions.")]
        public bool AllowExceptions
        {
            get
            {
                return _allowExceptions;
            }
            set
            {

                _allowExceptions = value;
            }
        }
        
        /// <summary>
        /// Get/Set of the Force Bulk Column Name
        /// </summary>
        [Description("Column Name that dictates a Force Bulk.")]
        public string ForceBulkColumnName
        {
            get
            {
                return _forceBulkColumn;
            }
            set
            {
            	_forceBulkColumn = value;
            }
        }
        /// <summary>
        /// Get/Set of the Force Standard Column Name
        /// </summary>
        [Description("Column Name that dictates a Force Standard Sync.")]
        public string ForceStandardColumnName
        {
            get
            {
                return _forceStandardColumn;
            }
            set
            {
                _forceStandardColumn = value;
            }
        }

        /// <summary>
        /// Get/Set of the Force Standard Column Name
        /// </summary>
        [Description("Column Name that is used to specify the object in salesforce.")]
        public string ObjectNameColumnName
        {
            get
            {
                return _objectColumnName; 
                
            }
            set
            {
            	_objectColumnName = value;
            }
        }

        /// <summary>
        /// Get/Set of the Whether to Send a change when DML is needed
        /// </summary>
        [Description("True/False to send Email when DML Changes need to be made.")]
        public bool SendDMLEmail
        {
            get
            {
                return _sendDML;
            }
            set
            {

                _sendDML = value;
            }
        }

        /// <summary>
        /// Get/Set the from email address
        /// </summary>
        [Description("An Email address to send DML emails from.")]
        public string FromAddress
        {
            get
            {
                return _fromAddress;
            }
            set
            {

                _fromAddress = value;
            }
        }

        /// <summary>
        /// Get/Set of the To email address
        /// </summary>
        [Description("An email address to send changes to")]
        public string ToAddress
        {
            get
            {
                return _toAddress;
            }
            set
            {

                _toAddress = value;
            }
        }

        /// <summary>
        /// Get/Set address of SMTP server
        /// </summary>
        [Description("An smtp Address to use in mailing")]
        public string SmtpAddress
        {
            get
            {
                return _smtp;
            }
            set
            {

                _smtp = value;
            }
        }
        #endregion

        #region Override Task Functions
        #region InitializeTask
        /// <summary>
        /// Initialize the task to pass in the connections. 
        /// </summary>
        /// <param name="connections">A list of connection managers in the package.</param>
        /// <param name="variableDispenser"></param>
        /// <param name="events"></param>
        /// <param name="log"></param>
        /// <param name="eventInfos"></param>
        /// <param name="logEntryInfos"></param>
        /// <param name="refTracker"></param>
        public override void InitializeTask(Connections connections, VariableDispenser variableDispenser, IDTSInfoEvents events, IDTSLogging log, EventInfos eventInfos, LogEntryInfos logEntryInfos, ObjectReferenceTracker refTracker)
        {
            //Logger.LogEvent("SFDC Refresh", "Initialize Task", System.Diagnostics.EventLogEntryType.Information);
            base.InitializeTask(connections, variableDispenser, events, log, eventInfos, logEntryInfos, refTracker);
            _connections = connections;
        }
        #endregion

        #region Execute
        /// <summary>
        /// Execute the task to refresh the salse force database.
        /// </summary>
        /// <param name="connections"></param>
        /// <param name="variableDispenser"></param>
        /// <param name="componentEvents"></param>
        /// <param name="log"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public override DTSExecResult Execute(Connections connections, VariableDispenser variableDispenser, IDTSComponentEvents componentEvents, IDTSLogging log, object transaction)
        {
            
            Logger.LogEvent("SFDC Refresh", "Begin executing Task", System.Diagnostics.EventLogEntryType.Information);
            DTSExecResult result = DTSExecResult.Success;
            ExceptionParameter exceptParam = new ExceptionParameter(_tableName, _columnName, _allowExceptions, _defaultStatus, _objectColumnName, _forceBulkColumn, _forceStandardColumn);
            DmlEmailParameter emailParam = new DmlEmailParameter(_sendDML, _fromAddress, _toAddress, _smtp);
            try

            {
                bool success = SFTask.DoTask(ReplicationTaskType.Refresh, _maxThread, _sqlConnectionString, _userName, _password, _batchSize,
                true, true, _manualComparison, _bulkApi, _bulkCutoff, _messageLevel, componentEvents, _maxRetries, exceptParam,emailParam);
                if (!success)
                {
                    result = DTSExecResult.Failure;
                }
            }
            catch (Exception ex)
            {
                result = DTSExecResult.Failure;
                SFTask.DisplayError(ex.Message);
                Logger.LogEvent("SFDC Refresh", ex.Message, System.Diagnostics.EventLogEntryType.Error);
            }
            Logger.LogEvent("SFDC Refresh", "Finish executing Task", System.Diagnostics.EventLogEntryType.Information);

            return result;
        }
        #endregion

        #region Validate
        /// <summary>
        /// Validate the properties. 
        /// </summary>
        /// <param name="connections"></param>
        /// <param name="variableDispenser"></param>
        /// <param name="componentEvents"></param>
        /// <param name="log"></param>
        /// <returns></returns>
        public override DTSExecResult Validate(Connections connections, VariableDispenser variableDispenser, IDTSComponentEvents componentEvents, IDTSLogging log)
        {
            //Logger.LogEvent("SFDC Refresh", "Validate all properties", System.Diagnostics.EventLogEntryType.Information);
            DTSExecResult result = DTSExecResult.Success;

            // validate oledb connection
            string error = ValidateSalesforceConnection();
            if (error != null && error != string.Empty)
            {
                componentEvents.FireError(0, "ValidateConnection", String.Format("Unable to connect to Salesforce database.{0}", error), string.Empty, 0);
                result = DTSExecResult.Failure;
            }

            // validate sql connection
            List<string> messages = ValidateSqlConnection(null);
            if (messages.Count > 0)
            {
                messages.ForEach(message => componentEvents.FireError(0, "ValidateConnection", message, string.Empty, 0));
                result = DTSExecResult.Failure;
            }

            // check the max number of the thread
            if (_maxThread > 5)
            {
                componentEvents.FireWarning(1, "ValidateParameter", "The suggested maximum number of Threads is set to greater than 5.", string.Empty, 0);
            }
            if (_maxThread < 1)
            {
                componentEvents.FireError(1, "ValidateParameter", "The suggested maximum number of Threads can not be set to less that 1.", string.Empty, 0);
                result = DTSExecResult.Failure;
            }

            if (_batchSize < 0)
            {
                componentEvents.FireError(1, "ValidateParameter", "The BatchSize can not be less than 0.", string.Empty, 0);
                result = DTSExecResult.Failure;
            }
            return result;

        }
        #endregion
        #endregion

        #region Private Functions
        #region ValidateSqlConnection
        /// <summary>
        /// Validate the Sql connection
        /// </summary>
        /// <returns>List of error message</returns>
        private List<string> ValidateSqlConnection(IDTSComponentEvents componentEvents)
        {
            //Logger.LogEvent("SFDC Refresh", "Validate Sql Connection", System.Diagnostics.EventLogEntryType.Information);

            List<string> messages = new List<string>();
            if (!_connections.Contains(_sqlDestConMgr))
            {
                messages.Add(String.Format("The specified SqlConnection \"{0}\" is either not valid object.To continue, specifiy a valid SqlConnection.", SqlDestinationConnectionName));
            }
            else
            {
                ConnectionManager cm2 = _connections[_sqlDestConMgr];
                Microsoft.SqlServer.Dts.Runtime.Wrapper.ConnectionManagerAdoNet cmadonet = cm2.InnerObject as Microsoft.SqlServer.Dts.Runtime.Wrapper.ConnectionManagerAdoNet;
                if (cmadonet == null)
                {
                    messages.Add(String.Format("{0} is not a ADO.NET Connection Manager.", SqlDestinationConnectionName));
                }
                else
                {
                    SqlConnection conn = null;
                    try
                    {
                        conn = cmadonet.AcquireConnection(null) as SqlConnection;
                        if (conn == null)
                        {
                            messages.Add(String.Format("The ADO.net connection Manager {0} does not reference a Sqlclient connection.", SqlDestinationConnectionName));
                        }
                        else
                        {

                            SqlCommand cmd = conn.CreateCommand();
                            cmd.CommandText = @"select has_perms_by_name(db_name(), 'DATABASE','CREATE TABLE')";
                            bool permission = Convert.ToBoolean(cmd.ExecuteScalar());
                            if (!permission)
                            {
                                messages.Add(String.Format("The specified SqlConnection \"{0}\" does not have the permission to create table.", SqlDestinationConnectionName));
                            }
                            cmd.CommandText = @"select has_perms_by_name(schema_name(), 'SCHEMA','CONTROL')";
                            permission = Convert.ToBoolean(cmd.ExecuteScalar());
                            if (!permission)
                            {
                                messages.Add(String.Format("The specified SqlConnection \"{0}\" does not have the permission to drop table.", SqlDestinationConnectionName));
                            }
                            _sqlConnectionString = conn.ConnectionString;
                        }
                    }
                    catch
                    {
                        messages.Add(String.Format("Invalid SqlConnection \"{0}", SqlDestinationConnectionName));
                    }
                    finally
                    {
                        if (conn != null)
                            conn.Close();
                    }
                }
            }
            return messages;

        }
        #endregion

        #region ValidateSalesforceConnection
        /// <summary>
        /// Validate sales force username and password and make sure the oledbconnection open with the username and password.
        /// </summary>
        /// <returns></returns>
        private string ValidateSalesforceConnection()
        {
            //Logger.LogEvent("SFDC Refresh", "Validate SF connection", System.Diagnostics.EventLogEntryType.Information);

            try
            {
                var sfSource = SalesForceConnectionFactory.Build(this.UserName, this.Password);
                return null;
            }
            catch (Exception ex)
            {
                return String.Format("Message: {0}StackTrace: {1}", ex.Message, ex.StackTrace);
            }
            

        }
        #endregion
        #endregion

        #region IDTSComponentPersist Members
        #region LoadFromXML
        /// <summary>
        /// Load all variables from the xml file.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="infoEvents"></param>
        public void LoadFromXML(XmlElement node, IDTSInfoEvents infoEvents)
        {
            //Logger.LogEvent("SFDC Refresh", "Load from XML", System.Diagnostics.EventLogEntryType.Information);
            if (node.Name != Constants.PERSIST_REFRESHELEMENT)
            {
                throw new Exception(string.Format("Unexpected task element when loading task - {0}.", Constants.PERSIST_REFRESHELEMENT));
            }
            else
            {
                _sqlDestConMgr = node.Attributes.GetNamedItem(Constants.PERSIST_SQLDESTCONMGR).Value;
                _batchSize = Convert.ToInt32(node.Attributes.GetNamedItem(Constants.PERSIST_BATCHSIZE).Value);
                _manualComparison = Convert.ToBoolean(node.Attributes.GetNamedItem(Constants.PERSIST_MANUALCOMPARISON).Value);
                _maxThread = Convert.ToInt32(node.Attributes.GetNamedItem(Constants.PERSIST_MAXTHREAD).Value);
                _maxRetries = Convert.ToInt32(node.Attributes.GetNamedItem(Constants.PERSIST_NUMRETRIES).Value);
                _bulkCutoff= Convert.ToInt32(node.Attributes.GetNamedItem(Constants.BULK_CUTOFF).Value);
                _bulkApi= Convert.ToBoolean(node.Attributes.GetNamedItem(Constants.USE_BULK_API).Value);
                _password = node.Attributes.GetNamedItem(Constants.PRESIST_PASSWORD).Value;
                _userName = node.Attributes.GetNamedItem(Constants.PERSIST_USERNAME).Value;
                _messageLevel = (ReportingLevel)Enum.Parse(typeof(ReportingLevel), node.Attributes.GetNamedItem(Constants.PERSIST_MESSAGELEVEL).Value);

                _allowExceptions = Convert.ToBoolean(node.Attributes.GetNamedItem(Constants.PERSIST_ALLOW_EXCEPTIONS).Value);
                _columnName = node.Attributes.GetNamedItem(Constants.PERSIST_EXCEPTION_COLUMN_NAME).Value;
                _tableName = node.Attributes.GetNamedItem(Constants.PERSIST_EXCEPTION_TABLE_NAME).Value;
                _forceBulkColumn = node.Attributes.GetNamedItem(Constants.PERSIST_EXCEPTION_FORCE_BULK_COLUMN_NAME).Value;
                _objectColumnName = node.Attributes.GetNamedItem(Constants.PERSIST_EXCEPTION_OBJECT_COLUMN_NAME).Value;
                _forceStandardColumn = node.Attributes.GetNamedItem(Constants.PERSIST_EXCEPTION_FORCE_STANDARD_COLUMN_NAME).Value;
                _defaultStatus = Convert.ToBoolean(node.Attributes.GetNamedItem(Constants.PERSIST_DEFAULT_STATUS).Value);

                _sendDML = Convert.ToBoolean(node.Attributes.GetNamedItem(Constants.PERSIST_SEND_DML_EMAIL).Value);
                _fromAddress = node.Attributes.GetNamedItem(Constants.PERSIST_DML_FROM_ADDRESS).Value;
                _toAddress = node.Attributes.GetNamedItem(Constants.PERSIST_DML_TO_ADDRESS).Value;
                _smtp = node.Attributes.GetNamedItem(Constants.PERSIST_DML_SMTP_ADDRESS).Value;

            }
        }
        #endregion

        #region SaveToXML
        /// <summary>
        /// Save all variables to the xml file.
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="infoEvents"></param>
        public void SaveToXML(XmlDocument doc, IDTSInfoEvents infoEvents)
        {
            //Logger.LogEvent("SFDC Refresh", "Save to XML", System.Diagnostics.EventLogEntryType.Information);
            // create node in the package xml document
            XmlElement taskElement = doc.CreateElement(string.Empty, Constants.PERSIST_REFRESHELEMENT, string.Empty);

            // Sql destination connection manager ID 
            XmlAttribute xaSqlDestConMgr = doc.CreateAttribute(string.Empty, Constants.PERSIST_SQLDESTCONMGR, string.Empty);
            xaSqlDestConMgr.Value = _sqlDestConMgr;
            taskElement.Attributes.Append(xaSqlDestConMgr);

            // batch size
            XmlAttribute xaBatchSize = doc.CreateAttribute(string.Empty, Constants.PERSIST_BATCHSIZE, string.Empty);
            xaBatchSize.Value = _batchSize.ToString();
            taskElement.Attributes.Append(xaBatchSize);

            // manual comparison
            XmlAttribute xaManualComparison = doc.CreateAttribute(string.Empty, Constants.PERSIST_MANUALCOMPARISON, string.Empty);
            xaManualComparison.Value = _manualComparison.ToString();
            taskElement.Attributes.Append(xaManualComparison);

            // max number of threads
            XmlAttribute xaMaxThread = doc.CreateAttribute(string.Empty, Constants.PERSIST_MAXTHREAD, string.Empty);
            xaMaxThread.Value = _maxThread.ToString();
            taskElement.Attributes.Append(xaMaxThread);

            // sales force user name
            XmlAttribute xaUserName = doc.CreateAttribute(string.Empty, Constants.PERSIST_USERNAME, string.Empty);
            xaUserName.Value = _userName;
            taskElement.Attributes.Append(xaUserName);

            // sales force password
            XmlAttribute xaPassword = doc.CreateAttribute(string.Empty, Constants.PRESIST_PASSWORD, string.Empty);
            xaPassword.Value = _password;
            taskElement.Attributes.Append(xaPassword);

            // message level
            XmlAttribute xaMessageLevel = doc.CreateAttribute(string.Empty, Constants.PERSIST_MESSAGELEVEL, string.Empty);
            xaMessageLevel.Value = _messageLevel.ToString();
            taskElement.Attributes.Append(xaMessageLevel);

            //MaxRetries
            XmlAttribute xaNumRetries = doc.CreateAttribute(string.Empty, Constants.PERSIST_NUMRETRIES, string.Empty);
            xaNumRetries.Value = this._maxRetries.ToString();
            taskElement.Attributes.Append(xaNumRetries);

            XmlAttribute xaBulkApi = doc.CreateAttribute(string.Empty, Constants.USE_BULK_API, string.Empty);
            xaBulkApi.Value = this._bulkApi.ToString();
            taskElement.Attributes.Append(xaBulkApi);

            XmlAttribute xaBulkCutoff = doc.CreateAttribute(string.Empty, Constants.BULK_CUTOFF, string.Empty);
            xaBulkCutoff.Value = this._bulkCutoff.ToString();
            taskElement.Attributes.Append(xaBulkCutoff);

            // TableName
            XmlAttribute tableName = doc.CreateAttribute(string.Empty, Constants.PERSIST_EXCEPTION_TABLE_NAME, string.Empty);
            tableName.Value = _tableName;
            taskElement.Attributes.Append(tableName);

            // ColumnName
            XmlAttribute columnName = doc.CreateAttribute(string.Empty, Constants.PERSIST_EXCEPTION_COLUMN_NAME, string.Empty);
            columnName.Value = _columnName;
            taskElement.Attributes.Append(columnName);

            //ForceBulk
            XmlAttribute ForceBulk = doc.CreateAttribute(string.Empty, Constants.PERSIST_EXCEPTION_FORCE_BULK_COLUMN_NAME, string.Empty);
            ForceBulk.Value = _forceBulkColumn;
            taskElement.Attributes.Append(ForceBulk);

            // ForceStandard
            XmlAttribute forceStandard = doc.CreateAttribute(string.Empty, Constants.PERSIST_EXCEPTION_FORCE_STANDARD_COLUMN_NAME, string.Empty);
            forceStandard.Value = _forceStandardColumn;
            taskElement.Attributes.Append(forceStandard);

            // Object ColumnName
            XmlAttribute objectCol = doc.CreateAttribute(string.Empty, Constants.PERSIST_EXCEPTION_OBJECT_COLUMN_NAME, string.Empty);
            objectCol.Value = _objectColumnName;
            taskElement.Attributes.Append(objectCol);

            // DefaultStatus
            XmlAttribute defaultStatus = doc.CreateAttribute(string.Empty, Constants.PERSIST_DEFAULT_STATUS, string.Empty);
            defaultStatus.Value = _defaultStatus.ToString();
            taskElement.Attributes.Append(defaultStatus);

            XmlAttribute allowExceptions = doc.CreateAttribute(string.Empty, Constants.PERSIST_ALLOW_EXCEPTIONS, string.Empty);
            allowExceptions.Value = _allowExceptions.ToString();
            taskElement.Attributes.Append(allowExceptions);


            XmlAttribute sendDmlEmail = doc.CreateAttribute(string.Empty, Constants.PERSIST_SEND_DML_EMAIL, string.Empty);
            sendDmlEmail.Value = _sendDML.ToString();
            taskElement.Attributes.Append(sendDmlEmail);


            XmlAttribute fromAddress = doc.CreateAttribute(string.Empty, Constants.PERSIST_DML_FROM_ADDRESS, string.Empty);
            fromAddress.Value = _fromAddress;
            taskElement.Attributes.Append(fromAddress);


            XmlAttribute toAddress = doc.CreateAttribute(string.Empty, Constants.PERSIST_DML_TO_ADDRESS, string.Empty);
            toAddress.Value = _toAddress;
            taskElement.Attributes.Append(toAddress);


            XmlAttribute smtpAddress = doc.CreateAttribute(string.Empty, Constants.PERSIST_DML_SMTP_ADDRESS, string.Empty);
            smtpAddress.Value = _smtp.ToString();
            taskElement.Attributes.Append(smtpAddress);



            doc.AppendChild(taskElement);
        }
        #endregion
        #endregion
    }
}